package top.sxlai.service.impl;

import top.sxlai.constant.OtherStatus;
import top.sxlai.entity.DTO.OpFileDTO;
import top.sxlai.entity.OpFile;
import top.sxlai.entity.OpFolder;
import top.sxlai.entity.OpUser;
import top.sxlai.interceptor.LoginInterceptor;
import top.sxlai.mapper.OpUserMapper;
import top.sxlai.service.IFileService;
import top.sxlai.util.CurrentSystemTime;
import top.sxlai.util.HandFileUtil;
import top.sxlai.util.JwtUtil;
import top.sxlai.util.hbase.HbaseDML;
import top.sxlai.util.hbase.ParameterInitializer;
import lombok.extern.slf4j.Slf4j;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : sxl
 * @date : 2024/4/13 9:11
 * @Version: 1.0
 */
@Service
@Slf4j
public class FileServiceImpl implements IFileService {
    @Autowired
    private OpUserMapper opUserMapper;
    @Autowired
    private FileSystem fileSystem;
    @Value("${hadoop.hdfsUrl}")
    private String hdfsUrl;
    @Value("${hbaseData.namespace}")
    private String namespace;
    @Value("${hbaseData.tables.folderTableName.tableName}")
    String folderTableName;
    @Value("${hbaseData.tables.folderTableName.columnFamily}")
    String folderColumnFamily;
    @Value("${hbaseData.tables.fileTableName.tableName}")
    String fileTableName;
    @Value("${hbaseData.tables.fileTableName.columnFamily}")
    String fileColumnFamily;
    /**
     * 上传文件
     *
     * @param file      文件
     * @param opFileDTO 数据
     * @return ResponseEntity
     * @throws Exception 异常
     */


    @Override
    public ResponseEntity<Map<String, String>> upLoadFile(MultipartFile file, OpFileDTO opFileDTO) throws Exception {
        // 设置 Hadoop 用户名
        System.setProperty("HADOOP_USER_NAME", "root");
        log.info("开始上传文件,文件名称:{},上传时间:{}", file.getOriginalFilename(), CurrentSystemTime.getTime());
        Map<String, String> response = new HashMap<>();
        if (file.isEmpty()) {
            response.put("message", OtherStatus.FAILURE.getMessage());
            return ResponseEntity.badRequest().body(response);
        }
        //获取用户id
        String userId = JwtUtil.parseJWT(LoginInterceptor.getToken()).getSubject();        //获取用户的账号信息
        OpUser userInfo = opUserMapper.getUserInfo(userId);
        //计算路径的文件id,判断是否是第一路径,如果第一路径是空的则先插入这个数据
        createFirstFolder(opFileDTO, userInfo);

        String localFilePath = "D:\\FileStore" + file.getOriginalFilename(); // 本地临时文件路径
        String hdfsFolderPath = opFileDTO.getFileFolderPath() + "/" + file.getOriginalFilename(); // HDFS 上的目标路径
        //判断本地临时存储路径是否存在
        File localFileDirectory = new File(localFilePath);
        if (!localFileDirectory.exists()) {
            localFileDirectory.mkdirs(); //创建
        }
        try {
//            Configuration conf = new Configuration();
//            conf.set("fs.defaultFS", hdfsUrl); // 设置 Hadoop 文件系统地址
//            FileSystem fileSystem = FileSystem.get(conf);
            //将文件临时保存到本地
            file.transferTo(localFileDirectory);
            //本地路径和HDFS文件夹路径
            Path localPath = new Path(localFilePath);
            Path hdfsPath = new Path(hdfsFolderPath);
            //上传文件
            fileSystem.copyFromLocalFile(localPath, hdfsPath);
            //上传文件数据到hbase
            uploadFileToHbase(file, opFileDTO, userInfo);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //删除本地临时文件
            File localFile = new File(localFilePath);
            if (localFile.exists()) {
                localFile.delete();
            }
        }
        log.info("文件上传成功,文件名称:{},时间:{}", file.getOriginalFilename(), CurrentSystemTime.getTime());
        response.put("message", OtherStatus.SUCCESS.getMessage());
        return ResponseEntity.ok(response);
    }

    @Override
    public ResponseEntity<List<OpFile>> queryFile(OpFileDTO opFileDto) throws IOException {
        //文件查询
        Map<String,String> response = new HashMap<>();
        log.info("开始查询文件,时间:{}", CurrentSystemTime.getTime());
        List<OpFile> opFileList = HbaseDML.filterScan(namespace, fileTableName, opFileDto.getFileFolderPath(),
                                                    fileColumnFamily, ParameterInitializer.getFileColumns(),
                                                    opFileDto.getSelectQueryWay(),"file");
        List<OpFile> collectOpFiles;
        if("1".equals(opFileDto.getSelectQueryWay())){  //1是按子级查询
            collectOpFiles = opFileList.stream().filter(opFile ->
                    opFile != null && opFile.getHdfsPath() != null
            ).collect(Collectors.toList());
        }else if("2".equals(opFileDto.getSelectQueryWay())){  //2是精确查询有关类型的文件
            collectOpFiles = opFileList.stream().filter(opFile ->
                    opFile != null && opFile.getHdfsPath() != null && Objects.equals(opFile.getTypeId(), opFileDto.getTypeId())
            ).collect(Collectors.toList());
        }else{ //查询全部
            collectOpFiles = opFileList.stream().filter(opFile ->
                    opFile != null && opFile.getHdfsPath() != null
            ).collect(Collectors.toList());
        }

        return ResponseEntity.ok(collectOpFiles);
    }
    /*
     * 创建初始文件夹文件夹
     * @param opFileDTO 数据
     * @param userInfo  用户信息
     * @throws IOException 异常
     */
    private void createFirstFolder(OpFileDTO opFileDTO, OpUser userInfo) throws IOException {
        int folderFirst = isFolderFirst(opFileDTO.getFileFolderPath());
        if (folderFirst == 1) {
            //先查询是否在hbase创建了该文件夹
            List<String> columNames = new ArrayList<>();
            columNames.add("folderName");
            columNames.add("folderId");
            columNames.add("userId");
            OpFolder isFolder = null;
            isFolder = HbaseDML.getFolderCells(namespace, folderTableName, opFileDTO.getFileFolderPath(), folderColumnFamily, columNames);
            //如果不存在，则插入这个数据
            if (isFolder.getFolderName() == null && isFolder.getFolderId() == null && isFolder.getUserId() == null) {
                log.info("开始创建初始文件夹:{}", CurrentSystemTime.getTime());
                //封装数据
                Map<String, String> colunmMap = new HashMap<>();
                //最初始的文件夹Id设置为1
                colunmMap.put("folderId", "1");
                //初始文件夹名称是用户名
                colunmMap.put("folderName", userInfo.getUsername());
                //父级设置为0
                colunmMap.put("parentId", "0");
                colunmMap.put("hdfsPath", opFileDTO.getFileFolderPath());
                colunmMap.put("owner", userInfo.getNickname());
                colunmMap.put("userId", String.valueOf(userInfo.getUserid()));
                colunmMap.put("createTime", CurrentSystemTime.getTime());
                colunmMap.put("status", "1");
                //给hbase添加最初的数据
                HbaseDML.putCell(namespace, folderTableName, opFileDTO.getFileFolderPath(), folderColumnFamily, colunmMap);
            }
        }
    }
    /**
     * 上传文件到hbase
     * @param file      文件
     * @param opFileDTO 数据
     * @param userInfo  用户信息
     * @throws IOException 异常
     */
    @Autowired
    private HandFileUtil handFileUtil;
    private void uploadFileToHbase(MultipartFile file, OpFileDTO opFileDTO, OpUser userInfo) throws Exception {
        //上传文件到hbase
        //获取文件类型
        String typeId = HandFileUtil.handFileToLocal(file);
        //获取文件的图像地址
        String filePath = opFileDTO.getFileFolderPath() + "/" + file.getOriginalFilename();
        //返回图像的imageUrl,不是图像的时候封装其他数据进去
        String imageUrl= "";
        if("4".equals(typeId)){
            imageUrl = handFileUtil.getFileBase64( filePath);
        }else {
            imageUrl = "#无效链接";
        }
        //封装数据
        Map<String, String> colunmMap = new HashMap<>();
        UUID uuid = UUID.randomUUID();
        colunmMap.put("fileId", uuid.toString());
        colunmMap.put("fileName", file.getOriginalFilename());
        colunmMap.put("folderId", String.valueOf(isFolderFirst(opFileDTO.getFileFolderPath()) + 1));
        colunmMap.put("typeId", typeId);
        colunmMap.put("userId", String.valueOf(userInfo.getUserid()));
        colunmMap.put("createTime", CurrentSystemTime.getTime());
        colunmMap.put("owner", userInfo.getUsername());
        colunmMap.put("status", "1");
        colunmMap.put("hdfsPath", opFileDTO.getFileFolderPath() + "/" + file.getOriginalFilename());
        colunmMap.put("imageUrl", imageUrl);
        double fileSizeInMB = (double) file.getSize() / (1024 * 1024);
        fileSizeInMB = Math.round(fileSizeInMB * 100.0) / 100.0; // 保留两位小数
        colunmMap.put("fileSize", String.valueOf(fileSizeInMB));

        String rowKey = opFileDTO.getFileFolderPath() +"/" +file.getOriginalFilename();
        HbaseDML.putCell(namespace, fileTableName, rowKey, fileColumnFamily, colunmMap);
    }
    //查询路径
    private int isFolderFirst(String fileFoldPath) {
        String[] folder = fileFoldPath.split("/");
        return folder.length;
    }
}
